﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using NLite.Reflection;
using System.Reflection;
using NLite;

namespace BLL
{
    static class Util
    {
        private static readonly BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase;

        private static Dictionary<int, MappingInfo> CreateMappings(IDataReader dataRecord, Type elementType)
        {
            var mappings = new Dictionary<int, MappingInfo>();
            var fieldCount = dataRecord.FieldCount;

            for (int i = 0; i < fieldCount; i++)
            {
                var columnName = dataRecord.GetName(i);
                var mapping = new MappingInfo { SourceType = dataRecord.GetFieldType(i) };

                var member = elementType.GetMember(columnName, flags).FirstOrDefault();
                if (member != null)
                {
                    mapping.SetMember = member.GetSetter();
                    mapping.TargetType = member.GetMemberType();
                    mappings.Add(i, mapping);
                }
            }
            return mappings;
        }

        public static ICollection<TEntity> ToList<TEntity>(this DataTable tb) where TEntity : new()
        {
            return ToList<TEntity>(tb.CreateDataReader());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="p"></param>
        /// <returns></returns>
        public static ICollection<TEntity> ToList<TEntity>(this IDataReader reader) where TEntity : new()
        {
            var items = new HashSet<TEntity>();
            var mappings = CreateMappings(reader, typeof(TEntity));

            while (reader.Read())
            {
                var item = new TEntity();

                foreach (var i in mappings.Keys)
                {
                    if (reader.IsDBNull(i))
                        continue;

                    var m = mappings[i];
                    var value = Mapper.Map(reader[i], m.SourceType, m.TargetType);

                    m.SetMember(item, value);
                }

                items.Add(item);
            }

            return items;
        }

        struct MappingInfo
        {
            public Type SourceType;
            public Type TargetType;

            public Setter SetMember;

        }
    }
}
